package org.altervista.cp.thinjdbc.wrappers;

import java.util.HashMap;
import java.util.LinkedList;

import org.altervista.cp.thinbcgen.proxy.Proxy;
import org.altervista.cp.thinbcgen.proxy.ProxyGenerator;
import org.altervista.cp.thinbcgen.proxy.UpdatableProxy;

@SuppressWarnings("unchecked")
public abstract class Wrapper<T> implements Proxy {

	protected final void wrap(T o) {
		((UpdatableProxy) this).proxy(o);
	}

	public T unwrap() {
		return (T) unproxy();
	}

	private static final boolean _JDBC4;
	static {
		boolean jdbc4 = false;
		try {
			Class.forName("java.sql.NClob");
			jdbc4 = true;
		} catch (ClassNotFoundException e) {
		}
		_JDBC4 = jdbc4;
	}

	private static final Class getWrapperClass(Class<?> c) {
		try {
			return _JDBC4 ? Class.forName(c.getName() + "4") : c;
		} catch (ClassNotFoundException e) {
			return c;
		} catch (Throwable t) {
			throw new IllegalStateException(t);
		}
	}

	protected static class _ProxyGenerator<T> extends ProxyGenerator {
		public T generate(Object source) {
			synchronized (_PROXY_CACHE) {
				String key = _targetClass.getName();
				LinkedList<T> proxyList = _PROXY_CACHE.get(key);
				if (proxyList == null) {
					proxyList = new LinkedList<T>();
					_PROXY_CACHE.put(key, proxyList);
				}
				if (proxyList.size() == 0) {
					return (T) super.generate(source);
				} else {
					T proxy = proxyList.removeLast();
					((UpdatableProxy) proxy).proxy(source);
					return proxy;
				}
			}
		}

		protected void release(T proxy) {
			synchronized (_PROXY_CACHE) {
				String key = _targetClass.getName();
				LinkedList<T> proxyList = _PROXY_CACHE.get(key);
				UpdatableProxy p = (UpdatableProxy) proxy;
				p.proxy(null);
				proxyList.addFirst(proxy);
			}
		}

		protected _ProxyGenerator(Class<T> targetClass) {
			super(getWrapperClass(targetClass), SQLRuntimeException.EH);
		}

		private final HashMap<String, LinkedList<T>> _PROXY_CACHE = new HashMap<String, LinkedList<T>>();

	}

}
